package org.codefinger.json.parser.deserializer;

import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.codefinger.json.JSONBase;
import org.codefinger.json.parser.JSONArrayDeserializer;
import org.codefinger.json.parser.JSONDeserializer;
import org.codefinger.json.parser.JSONLexer;
import org.codefinger.json.parser.JSONObjectDeserializer;
import org.codefinger.json.parser.JSONParseException;
import org.codefinger.json.parser.JSONParser;
import org.codefinger.json.util.IdentityCache;
import org.codefinger.json.util.IdentityCache.ValueBuilder;
import org.codefinger.json.util.Lang;
import org.codefinger.json.util.magic.MagicConstructor;
import org.codefinger.json.util.type.Generic;

public class DeserializerForMap implements JSONDeserializer {

	private static final IdentityCache<Type, InitializationDevice>	INIT_MAP	= new IdentityCache<Type, InitializationDevice>(new InitializationDeviceBuilder());

	private Type													type;

	public DeserializerForMap(Type type) {
		this.type = type;
	}

	@Override
	public Object stringValue(String value) {
		return null;
	}

	@Override
	public Object stringValue(JSONLexer jsonLexer) {
		jsonLexer.skipCurrentString();
		return null;
	}

	@Override
	public Object intValue(String value) {
		return null;
	}

	@Override
	public Object floatValue(String value) {
		return null;
	}

	@Override
	public Object falseValue() {
		return null;
	}

	@Override
	public Object trueValue() {
		return null;
	}

	@Override
	public JSONArrayDeserializer createArrayDeserializer() {
		return ArrayDeserializerForNull.INSTANCE;
	}

	@Override
	public JSONObjectDeserializer createObjectDeserializer() {
		InitializationDevice device = INIT_MAP.get(type);
		return new ObjectDeserializerForMap(device.newMap(), device.getKeyDeserializer(), device.getValueDeserializer(), device.getType());
	}

	private static class InitializationDevice {

		private MagicConstructor<?>	map;

		private JSONDeserializer	keyDeserializer;

		private JSONDeserializer	valueDeserializer;

		private Type				type;

		public InitializationDevice(MagicConstructor<?> map, JSONDeserializer keyDeserializer, JSONDeserializer valueDeserializer) {
			super();
			this.map = map;
			this.keyDeserializer = keyDeserializer;
			this.valueDeserializer = valueDeserializer;
		}

		@SuppressWarnings("unchecked")
		public Map<Object, Object> newMap() {
			return (Map<Object, Object>) map.newInstance();
		}

		public Type getType() {
			return type;
		}

		public JSONDeserializer getKeyDeserializer() {
			return keyDeserializer;
		}

		public JSONDeserializer getValueDeserializer() {
			return valueDeserializer;
		}

	}

	@Override
	public Object value(Integer value) {
		return null;
	}

	@Override
	public Object value(Double value) {
		return null;
	}

	@Override
	public Object value(Float value) {
		return null;
	}

	@Override
	public Object value(Long value) {
		return null;
	}

	@Override
	public Object value(Short value) {
		return null;
	}

	@Override
	public Object value(Byte value) {
		return null;
	}

	@Override
	public Object value(Boolean value) {
		return null;
	}

	@Override
	public Object value(Character value) {
		return null;
	}

	@Override
	public Object value(Date value) {
		return null;
	}

	@Override
	public Object value(BigDecimal value) {
		return null;
	}

	@Override
	public Object value(BigInteger value) {
		return null;
	}

	@Override
	public Object value(JSONBase value) {
		return null;
	}

	private static class InitializationDeviceBuilder implements ValueBuilder<Type, InitializationDevice> {

		@Override
		public InitializationDevice build(Type type) {

			Generic generic = Generic.getGeneric(type);

			Class<?> clazz = generic.getRealClass();

			MagicConstructor<?> map;

			if (clazz == Map.class) {
				map = MagicConstructor.getMagicConstructor(HashMap.class);
			} else {
				map = MagicConstructor.getMagicConstructor(clazz);
			}

			JSONDeserializer keyDeserializer;

			JSONDeserializer valueDeserializer;

			Type[] types = generic.getGenerics();

			if (types.length == 2) {
				keyDeserializer = JSONParser.getBasicDeserializer(types[0]);

				if (keyDeserializer == null) {
					throw new JSONParseException(//
							Lang.joinString("Can not support the type for the map key: ", type.toString()));
				}

				valueDeserializer = JSONParser.getDeserializer(types[1]);

			} else {
				keyDeserializer = DeserializerForString.INSTANCE;

				valueDeserializer = DeserializerForObject.INSTANCE;

			}

			return new InitializationDevice(map, keyDeserializer, valueDeserializer);

		}

	}

}
